变量

Unix shell 也有变量. 能对这些变量赋值, 也可以从这些变量取值.

变量的存储

要在 shell 里增加变量, 必须有个地方能存放这些变量的名称和值, 而且 这个变脸的存储系统必须能够分辨局部和全局变量.

struct var {
    char *str;  /* name = var string */
    int global; /* a boolean */
};
static struct var tab[MAXVARS];

增加变量命令: built-ins

set 是 shell 的一个命令, 而不是由 shell 运行的程序, 这就像 if 和then 这些关键字由 shell 自己处理一样.

修改 process 函数, 使之调用 fork/exec 之前检查是否为内置命令:

/* process.c
 * command processing layer
 *
 * The process(char **arglist) function is called by the main loop
 * It sits in  front of the execute() function. This layer handles
 * two main classes of processing:
 * a) built-in functions (e.g. exit(), set, =, read,..)
 * b) control structures (e.g. if, while, for)
 */
#include <stdio.h>
#include "smsh.h"

int is_control_command(char *);
int do_control_command(char **);
int ok_to_execute();

int
process(char **args)
/*
 * purpose: process user command
 * returns: result of processing command
 * details: if a built-in then call appropriate function, if not
 *          execute()
 * errors: arise form subroutines, handled there
 */
{
    int rv = 0;

    if (args[0] == NULL)
        rv = 0;
    else if (is_control_command(args[0]))
        rv = do_control_command(args);
    else if (ok_to_execute()){
        if (!builtin_command(args, &rv))
            rv = execute(args);
    }
    return rv;
}
添加 builtin.c 代码
/* builtin.c
 * contans the switch and the functions for built in commands
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "smsh.h"
#include "varlib.h"

int assign(char *);
int okname(char *);

int builtin_command(char **args, int *resultp)
/*
 * purpose: run a builtin command
 * returns: 1 if args[0] is builtin, 0 if not
 * details: test args[0] against all know built-ins. Call functions
 */
{
    int rv = 0;
    if (strcmp(args[0], "set") == 0){
        VLlist();
        *resultp = 0;
        rv = 1;
    }else if(strchr(args[0], '=') != NULL){
        *resultp = assign(args[0]);
        if (*resultp != -1)
            rv = 1;
    }else if (strcmp(args[0], "export") == 0){
        if (args[1] != NULL && okname(args[1]))
            *resultp = VLexport(args[1]);
        else
            *resultp = 1;
        rv = 1;
    }else if (strcmp(args[0], "unset") == 0){
        VLfree();
        rv = 1;
    }
    return rv;
}

int assign(char *str)
/*
 * purpose: execute name=val AND ensure that name is legal
 * returns: -1 for illegal lval, or result of VLstore
 * warning: modifies the string, but stores it to normal
 */
{
    char *cp;
    int rv;
    cp = strchr(str, '=');
    *cp = '\0';
    rv = (okname(str) ? VLstore(str, cp+1): -1);
    *cp = '=';
    return rv;
}

int okname(char *str)
/*
 * purpose: datermins if a string is a legal variable name
 * returns: 0 for no, 1 for yes
 */
{
    char *cp;
    for (cp=str; *cp; cp++){
        if ((isdigit(*cp) && cp == str) || !(isalnum(*cp) || *cp == '_'))
            return 0;
    }
    int rv = (cp != str); /* no empty strings, either */
    return  rv;
}

话说书中并没有提到 varlib.hvarlib.c 两个文件的源码, 所以我自己补了下面了个文 件.

varlib.h

#ifndef _VARLIB_H
#define _VARLIB_H
/* varlib.h
 */
#include <stdio.h>

struct var {
    char *name;
    char *val;
    int global;
};


void VLlist();
int VLexport(char *);
int VLstore(char *, char *);
struct var *VLfind(char *);
void VLfree();
#endif

varlib.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "smsh.h"
#include "varlib.h"

static struct var *VLBuf[BUFSIZ];
static int VLindex = 0;

int VLstore(char *name, char *val)
{
    if (VLindex >= BUFSIZ){
        return 0;
    }
    struct var *tmp;
    char *tn, *tv;
    tn = emalloc((strlen(name)+1) * sizeof(char));
    tv = emalloc((strlen(val) + 1) * sizeof(char));
    tn = strcpy(tn, name);
    tv = strcpy(tv, val);
    if ((tmp = VLfind(tn)) == NULL){
        tmp = emalloc(sizeof(struct var));
        tmp->name = tn;
        tmp->val = tv;
        tmp->global = 0;
        VLBuf[VLindex] = tmp;
        VLindex++;
    }else{
        tmp->val = tv;
    }
    return 0;
}

int VLexport(char *name)
{
    struct var *tmp;
    if ((tmp = VLfind(name)) == NULL){
        return 0;
    }else{
        tmp->global = 1;
        return 1;
    }
}

void VLlist()
{
    int i;
    for (i = 0; i < VLindex; i++){
        printf("%s=%s\n", VLBuf[i]->name, VLBuf[i]->val);
    }
}


struct var *VLfind(char *name)
{
    int i;
    for (i = 0; i < VLindex; i++){
        if (strcmp(VLBuf[i]->name, name) == 0){
            return VLBuf[i];
        }
    }
    return NULL;
}

void VLfree()
{
    int i;
    for (i = 0; i < VLindex; i++){
        free(VLBuf[i]->name);
        free(VLBuf[i]->val);
        free(VLBuf[i]);
    }
    VLindex = 0;
}

编译:

cc smsh2.c controlflow.c builtin.c splitline.c execute.c process.c varlib.c -o smsh3